﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using STEM123.StemService;

namespace STEM123
{
    /// <summary>
    /// Search results page.
    /// </summary>
    public partial class ResultsPage : PhoneApplicationPage
    {
        #region Private members

        /// <summary>
        /// Search view model.
        /// </summary>
        private SearchViewModel viewModel;

        /// <summary>
        /// Proxy to make webservice calls.
        /// </summary>
        private StemServiceClient client;

        /// <summary>
        /// List of pending actions.
        /// </summary>
        private Queue<Action> pendingActions;

        /// <summary>
        /// Hook to webservice events.
        /// </summary>
        private void hookToWebService()
        {
            this.client = new StemServiceClient();
            this.client.OpenCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_OpenCompleted);
            this.client.SearchCompleted += new EventHandler<SearchCompletedEventArgs>(client_SearchCompleted);
        }

        /// <summary>
        /// Unhook from webservice events.
        /// </summary>
        private void unhookFromWebService()
        {
            lock (pendingActions)
            {
                pendingActions.Clear();
            }

            this.client.OpenCompleted -= new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_OpenCompleted);
            this.client.SearchCompleted -= new EventHandler<SearchCompletedEventArgs>(client_SearchCompleted);
            this.client.CloseAsync();
        }

        /// <summary>
        /// Prepare search results.
        /// </summary>
        private void prepareSearch()
        {
            Dispatcher.BeginInvoke(() =>
            {
                System.Threading.Thread.Sleep(1000);

                lock (pendingActions)
                {
                    pendingActions.Clear();
                }

                this.searchResults();

                this.client.OpenAsync();
            });
        }

        /// <summary>
        /// Perform search asynchronously.
        /// </summary>
        private void searchResults()
        {
            // add to list of pending operations
            this.pendingActions.Enqueue(() =>
            {
                this.client.SearchAsync(string.Empty, this.viewModel.Term);
            });
        }

        /// <summary>
        /// Occurs when an item is selected.
        /// </summary>
        /// <param name="sender">Listbox reference.</param>
        /// <param name="e">Event specific arguments.</param>
        private void OnItemSelected(object sender, SelectionChangedEventArgs e)
        {
            ListBox listbox = ((ListBox)sender);
            SearchResultsItem item = (SearchResultsItem)listbox.SelectedItem;

            if (item != null)
            {
                // update model to select desired presentation
                SearchViewModel.Instance.SelectPresentation(item.Id);

                NavigationService.Navigate(new Uri("/ViewPresentation.xaml?view=" + ViewModels.Search, UriKind.Relative));
            }
        }

        /// <summary>
        /// Occurs when connection is opened with webservice.
        /// </summary>
        /// <param name="sender">Event related object.</param>
        /// <param name="e">Event specific arguments.</param>
        private void client_OpenCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else
            {
                // execute next action in queue
                Dispatcher.BeginInvoke(() =>
                {
                    lock (pendingActions)
                    {
                        if (pendingActions.Count > 0)
                        {
                            Action nextAction = this.pendingActions.Dequeue();
                            nextAction();
                        }
                    }
                });
            }
        }

        /// <summary>
        /// Occurs when search is completed.
        /// </summary>
        /// <param name="sender">Event related object.</param>
        /// <param name="e">Event specific arguments.</param>
        private void client_SearchCompleted(object sender, SearchCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                NavigationService.Navigate(new Uri("/MainSearchPage.xaml", UriKind.Relative));
            }
            else
            {
                SearchResults results = e.Result;

                Dispatcher.BeginInvoke(() => this.panResults.Title = viewModel.Term);

                this.viewModel.Results = results;

                if (e.Result.Presentations != null)
                {
                    List<SearchResultsItem> items = SearchResultsItem.GetSearchResults(results.Presentations);

                    Dispatcher.BeginInvoke(() =>
                    {
                        List<SearchResultsItem> itemsByDate = new List<SearchResultsItem>();
                        itemsByDate.AddRange(items);
                        this.lstByDate.ItemsSource = itemsByDate.OrderByDescending(item => item.PublishedOn);
                    });

                    Dispatcher.BeginInvoke(() =>
                    {
                        List<SearchResultsItem> itemsByViews = new List<SearchResultsItem>();
                        itemsByViews.AddRange(items);
                        this.lstByViews.ItemsSource = itemsByViews.OrderByDescending(item => item.TimesViewed);
                    });
                }
                else
                {
                    MessageBox.Show("Sorry, no presentations were found related to the term you entered.");
                    NavigationService.Navigate(new Uri("/MainSearchPage.xaml", UriKind.Relative));
                }
            }
        }

        #endregion

        #region Public members

        /// <summary>
        /// Initializes new instance of ResultsPage.
        /// </summary>
        public ResultsPage()
        {
            InitializeComponent();

            this.viewModel = SearchViewModel.Instance;
            this.pendingActions = new Queue<Action>();
        }

        #endregion

        #region Protected members

        /// <summary>
        /// Occurs when page is navigated to, from some other page.
        /// </summary>
        /// <param name="e">Navigation event arguments.</param>
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            // begin communication with webservice
            Dispatcher.BeginInvoke(() =>
                {
                    hookToWebService();
                    prepareSearch();
                });
        }

        /// <summary>
        /// Occurs when page is navigated from, to other page.
        /// </summary>
        /// <param name="e">Event specific arguments.</param>
        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            unhookFromWebService();

            base.OnNavigatedFrom(e);
        }

        #endregion
    }
}